package 单例模式.register;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;


public class EnumSingletonTest {

    /**
     * EnumSingleton 枚举不存在序列化反序列化，对象不一致问题
     *
     * 枚举式单例模式也是
     * Effective Java 书中推荐的一种单例模式实现写法。JDK 枚举的语法特殊性及反射也为枚举保驾护航。
     *
     * 优势如下：
     * 1、相对于反射破坏，jdk中的 newInstance方法规定不允许枚举调用此方法
     * 2、相对于多线程初始化破坏, 枚举式单例模式在静态代码块中就给 INSTANCE 进行了构造函数赋值（利用jad可以查看），
     *      是饿汉式单例模式的实现。和 HungryStaticSingleton 实现方式相同
     * 3、相对于序列化反序列化破坏，枚举类型其实通过类名和类对象类找到一个唯一的枚举对象。因此，枚举对象不可能被类加载器加载多次。
     */
    public static void main(String[] args) {
        try {
            EnumSingleton instance1;

            EnumSingleton instance2 = EnumSingleton.getInstance();
            instance2.setData(new Object());

            FileOutputStream fos = new FileOutputStream("EnumSingleton.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(instance2);
            oos.flush();
            oos.close();

            FileInputStream fis = new FileInputStream("EnumSingleton.obj");
            ObjectInputStream ois = new ObjectInputStream(fis);
            instance1 = (EnumSingleton) ois.readObject();
            ois.close();

            System.out.println(instance1.getData());
            System.out.println(instance2.getData());
            System.out.println(instance1.getData() == instance2.getData());


            try {
                // 枚举不能利用反射创建对象。jdk newInstance 规定
                Class clazz = EnumSingleton.class;
                Constructor c = clazz.getDeclaredConstructor(String.class, int.class);
                c.setAccessible(true);
                EnumSingleton enumSingleton = (EnumSingleton) c.newInstance("Tom", 666);

            } catch (Exception e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}